<?php
// +----------------------------------------------------------------------
// | Description: 创建符合restful风格的控制器
// +----------------------------------------------------------------------
// | Author: dongpeng
// +----------------------------------------------------------------------
namespace app\command;

use app\mysql\Schema;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

class RestConsole extends Command
{
    private $domain = "pshops.com/v1"; // api域名 + 版本号 

    protected function configure()
    {
        //设置参数(大小写敏感)
        $this->addArgument('moduleName', Argument::REQUIRED); //模块名称
        $this->addArgument('className', Argument::REQUIRED); //类名
        $this->addArgument('modelName', Argument::REQUIRED); //model类名
        $this->addArgument('tableName', Argument::REQUIRED); //表名
        // 选项
        $this->addOption('Description', 'd', Option::VALUE_REQUIRED, 'test'); //11111
        $this->addOption('Author', 'a', Option::VALUE_OPTIONAL, 'test'); //作者

        $this->setName('rest')->setDescription('create restFul API');
    }

    /**
     * 可以这样执行命令 php think rest front Blobs Blod front_blob -d"this is description"
     * @param Input $input
     * @param Output $output
     * <a href='/@return'>@小鱼儿</a> void;
     */
    protected function execute(Input $input, Output $output)
    {
        // 获取参数值
        $args = $input->getArguments();
        
        // 获取选项值
        $options = $input->getOptions();

        $Description = $options['Description'];

        $curdModel = file_get_contents(__DIR__ . '/../tpl/CurdModel.tpl');
        $RestController = file_get_contents(__DIR__ . '/../tpl/RestController.tpl');
        $CurdValidate = file_get_contents(__DIR__ . '/../tpl/CurdValidate.tpl');

        $all = $args + $options;
        $all['tableNameHump'] = preg_replace_callback('/([-_]+([a-z]{1}))/i', function ($matches) {
            return strtoupper($matches[2]);
        }, $all['tableName']);

        $schema = new Schema();

        // 判断表是否已经建立  已经创建这里直接跳过
        $tableName = $args['tableName'];
        $tableExist = $schema->tableExist("SELECT table_name FROM information_schema.TABLES WHERE table_name ='$tableName'");
        if (!count($tableExist)) {
            // 如果存在同名sql 则读取创建表的 sql 并运行  否则提示用户创建相关sql文件
            if (is_file(__DIR__ . '/../schema/' . $args['tableName'] . '.sql')) {
                // 运行这段sql语句 创建表
                $schema->createTable(__DIR__ . '/../schema/' . $args['tableName'] . '.sql');
            } else {
                $output->writeln('Lack of SQL files; name: ' . $args['tableName'] . '.sql' . " position: /applacation/schema/");die;
            }
        }

        $tableStruct = $schema->query("SHOW FULL FIELDS FROM " . $args['tableName']);

        $rule = '';
        $message = '';
        $params = [];
        $ListTable = '';
        $AddTable = '';
        $EditTable = '';
        $AddSelectData = [];
        $AddSelect = [];
        $uploadImg = [];
        $AddRules = [];
        foreach ($tableStruct as $k => $v) {
            $field = $v['Field'];
            $comment = $v['Comment'];
            $type = $v['Type'];

            if ($ListTable) {
                 $ListTable .= "
    | {$field} | {$type} | {$comment} |";
            } else {
                $ListTable = "| {$field} | {$type} | {$comment} |";
            }

            if ($v['Key'] != "PRI" and $v['Default'] === null) {

                $tHeader[]      = $comment;
                $filterVal[]    = $field;

                // 页面提交必填项
                if(strpos($comment, '(单选)') !== false){   // 如果注释中使用 (单选)  标明  则该项为单选项
                    $AddSelect[]   =  [ 'prop'=> $field, 'label'=> $comment ];
                    $AddSelectData[$field] = null;
                }else{
                    if(strpos($comment, '(图片)') !== false){  // 如果注释中使用 (图片)  标明  则该项为图片
                        $uploadImg = [ 'prop'=> $field, 'label'=> $comment ];
                    }else{
                        $AddInput[]   =  [ 'prop'=> $field, 'label'=> $comment ];
                    }
                    $AddForm[$field]   =  null; 
                }

                // char 类型
                if( strpos($type, 'char') !== false){
                    $AddRules[$field]  =  [[ 'required'=> true, 'message'=> "请输入".$comment ]];
                    $params[$field] = 'this is '.$field;
                }
                // int 类型
                if( strpos($type, 'int') !== false){
                    $params[$field] = 1;
                }

                if ($AddTable) {
                    $AddTable .= "
       | {$field} | {$type} | 是 |{$comment} |";
               } else {
                   $AddTable = "| {$field} | {$type} | 是 | {$comment} |";
               }

               if ($EditTable) {
                $EditTable .= "
   | {$field} | {$type} | 否 |{$comment} |";
           } else {
               $EditTable = "| {$field} | {$type} | 否 | {$comment} |";
           }

                if ($rule) {
                    $rule .= "
        '$field'        => 'require',";
                    $message .= "
        '{$field}.require'    => '请输入{$comment}',";
                } else {
                    $rule = "'$field'        => 'require',";
                    $message = "'{$field}.require'    => '请输入{$comment}',";
                }
            }
        }

        // 待替换变量
        $all['tableNameHump'] = ucfirst($all['tableNameHump']);
        $all['date'] = date("Y-m-d H:i:s");
        $all['rule'] = $rule;
        $all['message'] = $message;
        if (empty($all['Author'])) {
            $all['Author'] = "orchief";
        }
        
        // 替换变量
        foreach ($all as $k => $v) {
            $waitReplace[] = '{{$' . $k . '}}';
            $replace[] = $v;
        }
        $RestController = str_replace($waitReplace, $replace, $RestController);
        $curdModel = str_replace($waitReplace, $replace, $curdModel);
        $CurdValidate = str_replace($waitReplace, $replace, $CurdValidate);

        // 判断模块是否存在 不存在则创建
        $moduleName = $args['moduleName'];
        $className = $args['className'];

        $dir = iconv("UTF-8", "GBK", __DIR__ . '/../' . $args['moduleName']);
        if (!file_exists($dir)) {
            mkdir(__DIR__ . '/../' . $moduleName, 0775, true);
            mkdir(__DIR__ . '/../' . $moduleName . '/controller/', 0775, true);
            mkdir(__DIR__ . '/../' . $moduleName . '/model/', 0775, true);
            mkdir(__DIR__ . '/../' . $moduleName . '/validate/', 0775, true);
        }

        file_put_contents(__DIR__ . '/../' . $moduleName . '/controller/' . $className . '.php', $RestController);
        file_put_contents(__DIR__ . '/../' . $moduleName . '/model/' . $args['modelName'] . '.php', $curdModel);
        file_put_contents(__DIR__ . '/../' . $moduleName . '/validate/' . $all['tableNameHump'] . '.php', $CurdValidate);
        
        // 新增rest路由
        // $this -> genRoutes($args);
        
        $Description = iconv("GB2312", "UTF-8", $Description);
        
        $assigns = [
            'Description' => '描述信息',
            'moduleName' => $moduleName,
            'className' => $className,
        ];
        
        $assigns['ListTable'] = $ListTable;
        $assigns['AddTable'] = $AddTable;
        $assigns['EditTable'] = $EditTable;
        $assigns['IndexTable'] = $ListTable;
        // 对一个接口进行 基于restful风格的访问
        $assigns = $this -> restQuery($moduleName.'/'.$className, $assigns, $params, $output);
        
        $this->modifyApiMd(__DIR__ . '/../../api.md', $assigns);
        
        // 自动生成权限和菜单数据
        $AddTitle = '新增'.$Description;
        // 编辑
        $EditForm = $AddForm;

        $EditSelectData = $AddSelectData;

        $EditTitle = '编辑'.$Description;

        $EditInput   =   $AddInput;

        $EditSelect   =   $AddSelect;

        $EditRules = [];
        
        // 列表配置
        $baseApi = $moduleName.'/'.$className;
        $configFileName = $Description.'列表';
        
        $width  =  [200, 200, 200, 200];

        $search_input   =   [
            [
                'name'=> "field",
                'placeholder'=> "fieldName"
            ]
        ];
        $search_select   =   [
            [
                'name'          => "field",
                'placeholder'   => "fieldName",
                'multiple'      => false
            ]
        ];
        $searchReceived = [
            'status'    => [
                [
                    'label'=> "启用",
                    'value'=> "1"
                ],
                [
                    'label'=> "禁用",
                    'value'=> "0"
                ]
            ]
        ];

        $searchExchanged    =   [
            'limit'=> 10,
            'page'=> 1,
            'orderByString'=> ""
        ];
       
        // 配置数组
        $configArr = [
            'Add'       => [
                'dialogFormVisible' => false,
                'data'              => [
                    'primary'     => '',
                    'form'        => $AddForm,              // 新增字段
                    'selectData'  => $AddSelectData         // 有备选项的字段
                    ],
                'config'            => [
                    'uploadUrl'     => 'axios.defaults.baseUR + \'admin/upload\'',
                    'domain'        => 'axios.defaults.baseUR',
                    'title'     =>   $AddTitle,             // 新增标题
                    'form'      =>   [
                        'input'     =>  $AddInput,          // 新增文本项
                        'select'    =>  $AddSelect,         // 新增单选项
                        'uploadImg'     => $uploadImg
                    ],
                    'rules'     =>   $AddRules              // 新增限制规则
                ]
            ],
            'Edit'       => [
                'dialogFormVisible' => false,
                'data'              => [
                    'primary'     => '',
                    'form'        => $EditForm,              // 编辑字段
                    'selectData'  => $EditSelectData         // 有备选项的字段
                    ],
                'config'            => [
                    'uploadUrl'     => 'axios.defaults.baseUR + \'admin/upload\'',
                    'domain'        => 'axios.defaults.baseUR',
                    'title'     =>   $EditTitle,             // 编辑标题
                    'form'      =>   [
                        'input'     =>  $EditInput,          // 编辑文本项
                        'select'    =>  $EditSelect,          // 编辑单选项
                        'uploadImg'     => $uploadImg
                    ],
                    'rules'     =>   $AddRules               // 编辑限制规则
                ]
            ],
            'config'    => [
                'baseApi'   => $baseApi,
                'excel'     => [
                    'fileName'      =>      $configFileName,  // 导出的excel表格名称
                    'tHeader'       =>      $tHeader,         // 表头
                    'filterVal'     =>      $filterVal        // 字段名
                ],
                'table'     =>      [
                    'noGroup'   =>      true,
                    'checkbox'  =>      false,
                    'status'    =>      false, 
                    'sort'      =>      [
                        'field'     =>      "custom"
                    ],
                    'show'      =>      [
                        'items'     =>      $tHeader,
                        'prop'      =>      $filterVal,
                        'width'     =>      $width
                    ],
                    'operate'   =>      [
                        'del'       => true,
                        'edit'      => true
                    ]
                ],
                'search'    =>      [
                    'search_input'      =>      $search_input,
                    'search_select'     =>      [

                    ]
                ],
                'page'      =>      [
                    'limits'=> [5, 10, 20, 50, 100],
                    'layout'=> "total, sizes, prev, pager, next, jumper"
                ]
            ],
            'data'      => [
                'received'      =>      [
                    'table' =>[],
                    'count' => null,
                    'search'    =>      $searchReceived
                ],
                'exchanged'     =>      [
                    'search'            =>      $searchExchanged,
                    'multipleSelection' =>  [],
                    'isDelete'          => 0
                ]
            ]
        ];

        // json格式的配置文件
        $configJson = json_encode($configArr, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);

        file_put_contents(__DIR__.'/../jsonConfig/'.$args['className'].'.json', $configJson);

        // 返回成功信息
        $output->writeln('Generated Successfully!');
    }

    /* 同步的修改api文档
     *
     * @return void
     */
    public function modifyApiMd($filePath, $assigns)
    {
        // 检验api文档是否存在
        $this->checkFile($filePath);

        // 读取文档模板
        $api = file_get_contents(__DIR__ . '/../tpl/RestApi.tpl');

        // 处理模板变量
        // 替换变量
        foreach ($assigns as $k => $v) {
            $waitReplace[] = '{{$' . $k . '}}';
            $replace[] = $v;
        }
        
        $api = str_replace($waitReplace, $replace, $api);
        // 插入最新接口文档
        file_put_contents($filePath, $api, FILE_APPEND);
    }

    /**
     * 检查api文档是否存在 不存在则套用模板创建api文档
     *
     * @param [type] $filePath
     * @return void
     */
    public function checkFile($filePath)
    {
        if (!is_file($filePath)) {
            $baseApi = file_get_contents(__DIR__ . '/../tpl/BaseApi.tpl');
            file_put_contents($filePath, $baseApi);
        }
    }

    public function restQuery($path, $assigns, $params, $output)
    {
     
        $path = 'http://'.$this -> domain.'/'.$path;
        $curl = new \Curl\Curl();
        $curl -> setJsonDecoder(false);
        // Post Add
        $curl->post($path, $params);
        if ($curl->error) {
            dump('url:'.$path);
            dump($params);
            $output->writeln('Post data to api failed. Please check the web server!');die;
        } else {
            // 美化json
            $res = json_decode($curl->response, true);   
            $resJson = json_encode($res, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
            $assigns['AddRes'] = $resJson;
        }
    
        // Get List
        $curl->get($path);
        if ($curl->error) {
            $output->writeln('Get dataList from api failed. Please check the web server!');die;
        } else {
            // 美化json
            $res = json_decode($curl->response, true);
            if($res['code'] == 200 and count($res['data']['list']) >= 1 ) {
                $id = $res['data']['list'][0]['Id'];
                $assigns['ListRes'] = json_encode($res, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
            }else{
                dump('url:'.$path);
                dump($params);
                $output->writeln('Get dataList from api failed. Please check the web server!');die;
            }
        }

        // PUT Ddit
        foreach($params as $k => $v){
            if(is_string($params[$k])){
                $params[$k] = $params[$k]." modified";
            }
            if(is_int($params[$k])){
                $params[$k] = $params[$k] + 1;
            }
        }
        $curl->put($path."/".$id, $params);
        if ($curl->error) {
            $output->writeln('Put data to api failed. Please check the web server!');die;
        } else {
            // 美化json
            $res = json_decode($curl->response);   
            $resJson = json_encode($res, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
            // p($resJson);
            $assigns['EditRes'] = $resJson;
        }

        // Get Index
        $curl->get($path."/".$id);
        if ($curl->error) {
            $output->writeln('Get one items from api failed. Please check the web server!');die;
        } else {
            // 美化json
            $res = json_decode($curl->response);   
            $assigns['IndexRes'] = json_encode($res, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
        }

        return $assigns;
    }


    /**
     * 自动生成路由
     *
     * @return void
     */
    public function genRoutes($args)
    {
        $route = file_get_contents(__DIR__ . '/../../config/route_client.php');
        $regex = "/'__rest__'(.*?)=>(.*?)\[.+\],/Uis";
        preg_match($regex, $route, $matches);
        $strMatches = $matches[0];
        $moduleName = $args['moduleName'];
        $className = $args['className'];
        // 检查该路由是否已经存在
        $count = substr_count($strMatches, "{$moduleName}/{$className}");

        if ($count != 2) {
            $strMatches = substr_replace($strMatches, "'{$moduleName}/{$className}'								=>'{$moduleName}/{$className}',
        ],", -2);
            $res = preg_replace($regex, $strMatches, $route);

            file_put_contents(__DIR__ . '/../../config/route_client.php', $res);
        }
    }
}